/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 *
 */

import fs from 'fs';
import os from 'os';
import path from 'path';

import { CopyOptions, PatternObjType } from '../tasks/worker/copy-job.js';
import { minimatch } from 'minimatch';

export interface CopyConfig {
  /**
   * 是否为预览模式
   */
  isPreview?: boolean;

  /**
   * 当前编译任务所属模块到ets目录的路径,例如：entry/src/main/ets
   */
  aceModuleRoot: string;

  /**
   * 当前编译任务的build目录
   */
  aceModuleBuild?: string;

  /**
   * 当前编译任务的abilityType，仅限fa模型存在
   */
  abilityType?: string;

  /**
   * 当前编译任务的manifest.json的路径
   */
  aceManifestPath?: string;

  /**
   * 编译任务缓存的路径
   */
  cachePath?: string;

  /**
   * resourceTable.txt的路径
   */
  appResource?: string;

  /**
   * copyCodeResource: 用户配置的静态资源复制文件使能以及过滤规则
   */
  copyCodeResourceEnable?: boolean;
  copyCodeResourceExcludes?: string[];
}

export function getCopyOptions(copyConfig: CopyConfig): CopyOptions {
  copyConfig.isPreview ??= false;
  const patternObjTypes: PatternObjType[] = [];
  const BUILD_SHARE_PATH = '../share';
  const projectPath = copyConfig.aceModuleRoot;
  const buildPath = copyConfig.aceModuleBuild || path.resolve(projectPath, 'build');
  const defaultExcludes = ['**/*.ets', '**/*.ts', '**/*.js'];
  const userExcludes = copyConfig.copyCodeResourceExcludes ?? [];
  // 合并并去重
  const excludes = Array.from(new Set([...defaultExcludes, ...userExcludes]));
  patternObjTypes.push({
    src: path.resolve(projectPath, '**/*'),
    dest: buildPath,
    ignore: {
      ignored: (p) => {
        const regex = /\.ets$|\.ts$|\.js$/;
        return regex.test(p.name) || excludes.some((pattern) => minimatch(path.resolve(p.path, p.name), pattern, { dot: true }));
      },
    },
    onlyFiles: true,
    rename: renameDestFile(projectPath),
  });

  const sharePath: string = path.resolve(projectPath, BUILD_SHARE_PATH);
  if (fs.existsSync(sharePath)) {
    patternObjTypes.push({
      src: path.resolve(sharePath, '**/*'),
      dest: path.resolve(buildPath, BUILD_SHARE_PATH),
      ignore: {
        ignored: (p) => {
          const regex = /\.ets$|\.ts$|\.js$/;
          return regex.test(p.name);
        },
      },
      onlyFiles: true,
      rename: renameDestFile(sharePath),
    });
  }

  const abilityType = copyConfig.abilityType ?? 'page';
  if (abilityType === 'page' && copyConfig.aceManifestPath && fs.existsSync(copyConfig.aceManifestPath)) {
    patternObjTypes.push({
      src: copyConfig.aceManifestPath,
      dest: buildPath,
    });
  }

  const xtsMode = /ets_loader_ark$/.test(__dirname);
  const cachePath = copyConfig.cachePath ?? path.resolve(__dirname, 'node_modules/.cache');
  if (copyConfig.appResource && fs.existsSync(copyConfig.appResource) && !xtsMode && copyConfig.isPreview) {
    patternObjTypes.push({
      src: path.resolve(__dirname, copyConfig.appResource),
      dest: path.resolve(__dirname, cachePath),
    });
  }

  return { targets: formatCopyPatterns(patternObjTypes) };
}

function renameDestFile(prefixPath: string) {
  return (name: string, extension: string, fullPath: string) => {
    fullPath = toUnixPath(fullPath);
    const unixPrefixPath = toUnixPath(prefixPath);
    if (fullPath.indexOf(unixPrefixPath) !== -1) {
      let path = fullPath.replace(unixPrefixPath, '');
      if (path.startsWith('/')) {
        path = path.substring(1);
      }
      return path;
    }
    return `${name}.${extension}`;
  };
}

function formatCopyPatterns(patternObjTypes: PatternObjType[]) {
  patternObjTypes.forEach((item) => {
    item.src = toUnixPath(item.src);
    item.dest = toUnixPath(item.dest);
  });
  return patternObjTypes;
}

export function toUnixPath(data: string) {
  return os.type() === 'Windows_NT' ? path.posix.join(...data.split(path.sep)) : data;
}
